package mh.entity.object;

import java.util.Vector;

import mh.entity.Entity;
import mh.entity.IPickAndCollect;
import mh.entity.object.attributes.ObjectAttribute;
import mh.entity.object.attributes.ObjectAttributeWalkable;
import mh.map.objectset.ObjectSet;

public abstract class EntityObject extends Entity implements IPickAndCollect {
	/** The height of this item used to calculate effects of the spells */
	protected final EnumEntityObjectSize	height;

	/** True if the item can be moved */
	protected final boolean					movable;

	/** True if the item can normally move but is blocked for some reason */
	protected boolean						blocked;

	/** The amount of reflection this item has against spells. Value between 0 and 1 */
	protected final double					reflection;

	/** True if the item can be picked up */
	protected boolean						pickable;

	/** True if the item, once picked up, can be stacked toghether with items of the same type */
	protected boolean						collectable;

	protected ObjectSet						objectset;

	/** Array of attributes of the object */
	protected Vector<ObjectAttribute>		attributes;	//TODO probably will be implemented in a static way

	public EntityObject(int damageThreshold, int maximumHealth, int weight, EnumEntityObjectSize h, boolean canMove, double reflection, boolean pickable, boolean collectable) {
		super(true, damageThreshold, maximumHealth, true, weight);
		this.height = h;
		this.movable = canMove;
		this.blocked = !canMove;
		this.reflection = reflection;
		this.pickable = pickable;
		this.collectable = collectable;
		this.attributes = new Vector<ObjectAttribute>();
		this.setAttributes(); //sets the attributes (defined in all the children)
	}

	/**
	 * Copy constructor. Used to get an editable copy object of the argument.
	 * 
	 * @param e
	 *            The <code>EntityObject</code> to clone
	 */
	public EntityObject(EntityObject e) {
		super(true, e.damageThreshold, e.maximumHealth, true, e.weight);
		this.height = e.height;
		this.movable = e.movable;
		this.blocked = e.blocked;
		this.reflection = e.reflection;
		this.pickable = e.pickable;
		this.collectable = e.collectable;
	}

	@Override
	public boolean collide(Entity with) {
		return false;
	}

	/**
	 * Tells the object what tileset has to use.
	 * 
	 * @param objs
	 *            The <code>ObjectSet</code>
	 */
	public void setObjectSet(ObjectSet objs) {
		this.objectset = objs;
	}

	/**
	 * @return True if the health of this object is 0 and can be broken.
	 */
	public boolean isBroken() {
		return (this.actualHealth == 0) && (this.actualHealth != this.maximumHealth);
	}

	@Override
	public boolean isWalkable() {
		return true; //TODO if broken can be walked
	}

	/**
	 * @return The height of this item
	 */
	public EnumEntityObjectSize getHeight() {
		return this.height;
	}

	/**
	 * @return True if the object can be moved by a player or by a mob
	 */
	public boolean isMovable() {
		return this.movable && !this.blocked;
	}

	/**
	 * @return True if the object is blocked.
	 */
	public boolean isBlocked() {
		return this.blocked;
	}

	/**
	 * Prevents the item to move if movable
	 */
	public void lockMovement() {
		this.blocked = true;
	}

	/**
	 * Allows the item to move if locked
	 */
	public void releaseMovement() {
		if (this.movable) {
			this.blocked = false;
		}
	}

	/**
	 * @return The amount of reflection of this item. Value between 0 and 1
	 */
	public double reflectionAmount() { //TODO maybe will be added next
		return this.reflection;
	}

	/**
	 * @return True if the item can be picked up. //TODO MOVE FROM HERE?
	 */
	@Override
	public boolean isPickable() {
		return this.pickable;
	}

	/**
	 * @return True if the item once picked up can be grouped with same items in the bag.
	 */
	@Override
	public boolean isCollectable() {
		return this.collectable;
	}

	/**
	 * Adds an attribute for the current object instance
	 * 
	 * @param a
	 */
	protected void addAttribute(ObjectAttribute a) {
		int pos;
		boolean found = false;
		for (pos = 0; pos < this.attributes.size(); pos++) {
			if (this.attributes.get(pos).equals(a)) {
				found = true;
				break;
			}
		}

		if (found) {
			this.attributes.set(pos, a);
		} else {
			this.attributes.add(a);
		}
	}

	/**
	 * Sets the attributes for the current object
	 */
	protected abstract void setAttributes();

	/**
	 * Returns true if the Entity <code>e</code> can step over from its direction
	 * 
	 * @param e
	 * @return
	 */
	public boolean canStepOver(Entity e) {
		ObjectAttribute attr = null;
		for (ObjectAttribute o : this.attributes) {
			if (o instanceof ObjectAttributeWalkable) {
				attr = o;
			}
		}

		if (attr == null) {
			return true;
		} else {
			return attr.isValid(e);
		}

	}
}
